package online.sixfish.question.service.impl;


import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import online.sixfish.common.netty.NioWebSocketHandler;
import online.sixfish.common.pojo.State;
import online.sixfish.common.utils.SecurityUtil;
import online.sixfish.common.utils.SnowflakeIdWorker;
import online.sixfish.judger.judger.Judger;
import online.sixfish.judger.pojo.*;
import online.sixfish.judger.utils.ContainerUtils;
import online.sixfish.question.mapper.*;
import online.sixfish.question.model.MatchResult;
import online.sixfish.question.model.TestSamples;
import online.sixfish.question.model.entity.MockMatchRecord;
import online.sixfish.question.model.entity.QueProgram;
import online.sixfish.question.model.entity.QueProgramRecord;
import online.sixfish.question.service.JudgeService;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class JudgeServiceImpl implements JudgeService {
    @Autowired
    public ContainerUtils containerUtils;

    @Resource
    QueProgramRecordMapper queProgramRecordMapper;

    @Resource
    public RecordMapper recordMapper;


    @Resource
    public QuestionMapper questionMapper;

    @Resource
    private QueProgramMapper queProgramMapper;

    @Resource
    private MockMatchRecordMapper mockMatchRecordMapper;


    @Override
    public TestResult matchJudge(TestPack testPack) {
        // TODO 判断比赛开始没 健壮性
        return doJudge(testPack);
    }

    @Override
    public TestResult normalJudge(TestPack testPack) {
        return doJudge(testPack);
    }

    @Override
    public TestResult doJudge(TestPack testPack) {
        log.info("userWebSocketId:{}", NioWebSocketHandler.userWebSocketId);
//        NioWebSocketHandler.textWebSocketFrameHandler(
//                NioWebSocketHandler.userWebSocketId.get(String.valueOf(testPack.getUid())),
//                "1", "初始化...", "初始化完成"
//        );
        //创建时间
        Long time = System.currentTimeMillis();
        //拉取测试样例

        List<TestSample> testSamples = getTestSamples(testPack.getQid());

        testPack.setTestSampleList(testSamples);
        // 时间内空间
        testPack.setMemoryLimit(questionMapper.getQuestionMemoryLimit(testPack.getQid()));
        testPack.setTimeLimit(questionMapper.getQuestionTimeLimit(testPack.getQid()) * 1000);
//          对测试对象进行设置
        testPack.setSubmitTime(time);
        testPack.setSubmitTimeFormat(
                new SimpleDateFormat("yyyy-MM-dd- HH:mm:ss").format(time)
        );

//        测试结果
        TestResult testResult;
        try {
            //          新建判题机运行
            Judger judger = new Judger(testPack);
            testResult = judger.run();
            log.info("testResult:{}", testResult);
        } finally {
            //        删除判题机（异步）
            containerUtils.deleteContainer(testPack.getContainerId());
        }
//        保存记录

        return testResult;

    }

    /**
     * 编译后相关设置
     * 如 用户解题数量增加
     * 题目通过梳理增加
     * 保存编译记录等
     *
     * @param testResult
     * @param testPack
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean setting(TestResult testResult, TestPack testPack) {
        boolean flag = false;
//        报存编译记录
        flag = saveSubmitRecord(new SubmitRecord(
                SnowflakeIdWorker.snowFlow.nextId(),
                testResult.getUid(),
                testResult.getQid(),
                testPack.getQuestionName(),
                testResult.getTime(),
                testResult.getMemory(),
                testPack.getLanguage(),
                testPack.getCode(),
                testPack.getSubmitTimeFormat(),
                testResult.getTitle(),
                testResult.getMessage(),
                testResult.getTestSample() == null ? "{}" :
                        String.format("{\"input\":\"%s\",\"output\":\"%s\",\"userOutput\":\"%s\"}",
                                testResult.getTestSample().getInput(),
                                testResult.getTestSample().getOutput(),
                                testResult.getTestSample().getUserOutput()
                        ),
                testPack.getUserName()
        ));


        return flag;
    }

    /**
     * 必要设置，不参与事务回滚
     *
     * @param testResult
     * @param testPack
     * @return
     */
    public boolean mustSetting(TestResult testResult, TestPack testPack) {
        //更改题目总尝试\总通过
        boolean b = questionMapper.addTotalCount(
                testResult.isPass() ? 1 : 0, 1, testPack.getQid()
        );

        return b;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean settingForMatch(TestResult testResult, TestPack testPack) {
        boolean flag = false;
        SubmitRecord submitRecord = new SubmitRecord(
                SnowflakeIdWorker.snowFlow.nextId(),
                testResult.getUid(),
                testResult.getQid(),
                testPack.getQuestionName(),
                testResult.getTime(),
                testResult.getMemory(),
                testPack.getLanguage(),
                testPack.getCode(),
                testPack.getSubmitTimeFormat(),
                testResult.getTitle(),
                testResult.getMessage(),
                testResult.getTestSample() == null ? "{}" :
                        String.format("{\"input\":\"%s\",\"output\":\"%s\",\"userOutput\":\"%s\"}",
                                testResult.getTestSample().getInput(),
                                testResult.getTestSample().getOutput(),
                                testResult.getTestSample().getUserOutput()
                        ),
                testPack.getUserName());
//        记录比赛时提交记录
        flag = recordMapper.addMatchRecord(submitRecord, testPack.getMid());
//        普通的编译记录也要保存
        flag = saveSubmitRecord(submitRecord);


//        更新结果
        MatchResult userMatchResult = recordMapper.getUserMatchResult(testPack.getMid(), testPack.getUid());
        JSONObject jsonObject = new JSONObject(userMatchResult.getResults());
        log.info("{}", testResult);
        if (State.RECORD_AC_MARK.equals(jsonObject.get(String.valueOf(testPack.getQid())))) {
//            已经通过了，就不用进行接下来的操作
            return flag;
        }
        jsonObject.put(String.valueOf(testResult.getQid()), testResult.getTitle());
        userMatchResult.setResults(jsonObject.toString());
//        通过加分
        if (testResult.isPass()) {
            userMatchResult.setTotalScore(userMatchResult.getTotalScore() + 1);
        }
        log.info("{}", userMatchResult);
        recordMapper.updateUserMatchResult(userMatchResult);
//        没通过减分
        return flag;
    }

    @Override
    public void updateExperienceAndLevel(long qid, long uid) {
        String questionDifficulty = questionMapper.getQuestionDifficulty(qid);
        int experience = 0;
        switch (questionDifficulty) {
            case "简单":
                experience = 100;
                break;
            case "中等":
                experience = 200;
                break;
            case "困难":
                experience = 300;
                break;
            case "噩梦":
                experience = 500;
                break;
            default:
                experience = 0;
        }

    }

    @Override
    public TestResult judgeProgram(JudgeProgramReq judgeProgramReq) {
        TestPack testPack = new TestPack();
        BeanUtils.copyProperties(judgeProgramReq,testPack);
        long time = System.currentTimeMillis();
        //find 编程题
        QueProgram queProgram = queProgramMapper.selectById(judgeProgramReq.getQuestionId());
        //formatter test-case
        List<TestSample> sampleList = formatterTestSampleData(queProgram.getInputSampleData(),
                queProgram.getOutputSampleData());
        testPack.setTestSampleList(sampleList);
        //时间 空间
        testPack.setMemoryLimit(queProgram.getMemoryLimit());
        testPack.setTimeLimit(queProgram.getTimeLimit()* 1000);
        //对测试对象进行设置
        testPack.setSubmitTime(time);
        testPack.setSubmitTimeFormat(
                new SimpleDateFormat("yyyy-MM-dd- HH:mm:ss").format(time)
        );

        //测试结果
        TestResult testResult;
        try {
            //新建判题机运行
            Judger judger = new Judger(testPack);
            testResult = judger.run();
            log.info("testResult:{}", testResult);
        } finally {
            //删除判题机（异步）
            containerUtils.deleteContainer(testPack.getContainerId());
        }
        //保存记录
        //todo
        QueProgramRecord record = new QueProgramRecord();
        BeanUtils.copyProperties(testResult,record);
        record.setUserId(SecurityUtil.currentUserId());
        record.setQueProgramId(judgeProgramReq.getQuestionId());
//        record.setCodeType();
        queProgramRecordMapper.insert(record);

        return testResult;
    }

    @Override
    public TestResult judgeMatchProgram(JudgeProgramReq judgeProgramReq, String matchId) {
        TestPack testPack = new TestPack();
        BeanUtils.copyProperties(judgeProgramReq,testPack);
        long time = System.currentTimeMillis();
        //find 编程题
        QueProgram queProgram = queProgramMapper.selectById(judgeProgramReq.getQuestionId());
        //formatter test-case
        List<TestSample> sampleList = formatterTestSampleData(queProgram.getInputSampleData(),
                queProgram.getOutputSampleData());
        testPack.setTestSampleList(sampleList);
        //时间 空间
        testPack.setMemoryLimit(queProgram.getMemoryLimit());
        testPack.setTimeLimit(queProgram.getTimeLimit()* 1000);
        //对测试对象进行设置
        testPack.setSubmitTime(time);
        testPack.setSubmitTimeFormat(
                new SimpleDateFormat("yyyy-MM-dd- HH:mm:ss").format(time)
        );

        //测试结果
        TestResult testResult;
        try {
            //新建判题机运行
            Judger judger = new Judger(testPack);
            testResult = judger.run();
            log.info("testResult:{}", testResult);
        } finally {
            //删除判题机（异步）
            containerUtils.deleteContainer(testPack.getContainerId());
        }
        //保存记录
        //todo
        QueProgramRecord record = new QueProgramRecord();
        BeanUtils.copyProperties(testResult,record);
        record.setUserId(SecurityUtil.currentUserId());
        record.setQueProgramId(judgeProgramReq.getQuestionId());
//        record.setCodeType();
        queProgramRecordMapper.insert(record);
        Integer recordId = record.getId();


        MockMatchRecord matchRecord = mockMatchRecordMapper.selectById(matchId);
        String recordList = matchRecord.getRecordList();
        if(StringUtils.isBlank(recordList)){
            List<Integer> list = new ArrayList<>();
            list.add(recordId);
            String jsonArray = JSON.toJSONString(list);
            MockMatchRecord matchRecord1 = new MockMatchRecord();
            matchRecord1.setId(Integer.valueOf(matchId));
            matchRecord1.setRecordList(jsonArray);
            mockMatchRecordMapper.updateById(matchRecord1);
        }else {
            List<Integer> list = JSON.parseArray(recordList, Integer.class);
            list.add(recordId);
            String jsonArray = JSON.toJSONString(list);
            MockMatchRecord matchRecord1 = new MockMatchRecord();
            matchRecord1.setId(Integer.valueOf(matchId));
            matchRecord1.setRecordList(jsonArray);
            mockMatchRecordMapper.updateById(matchRecord1);

        }

        return testResult;
    }

    private List<TestSample> formatterTestSampleData(String inputSampleData, String outputSampleData) {
        JSONArray inputs = new JSONArray(inputSampleData);
        JSONArray outputs = new JSONArray(outputSampleData);
        List<TestSample> testSample = new ArrayList<>();
        //遍历组装
        for (int i = 0; i < inputs.length(); i++) {
            testSample.add(new TestSample(
                    1,
                    inputs.get(i).toString(),
                    outputs.get(i).toString(),
                    "",
                    false
            ));
        }
        return testSample;
    }

    /**
     * 得到问题 并 将测试用例格式化为数组
     *
     * @param id 题目id
     * @return 测试用例集合
     */
    @Override
    public List<TestSample> getTestSamples(long id) {
        TestSamples testSamples = questionMapper.getTestSample(id);
//        json解码
        JSONArray inputs = new JSONArray();
        JSONArray outputs = new JSONArray();
        if (testSamples != null) {
            inputs = new JSONArray(testSamples.getSampleInput());
            outputs = new JSONArray(testSamples.getSampleOutput());
        }

        List<TestSample> testSample = new ArrayList<>();
//        遍历组装
        for (int i = 0; i < inputs.length(); i++) {
            testSample.add(new TestSample(
                    id,
                    inputs.get(i).toString(),
                    outputs.get(i).toString(),
                    "",
                    false
            ));
        }

        return testSample;
    }

    @Override
    public boolean saveSubmitRecord(SubmitRecord submitRecord) {
        return recordMapper.addRecord(submitRecord);
    }


}
